﻿using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Practices.EnterpriseLibrary.Validation;
using Microsoft.Practices.EnterpriseLibrary.Validation.Validators; 

namespace Sinacor.Infra.Service.Validation
{
    /// <summary>
    /// Classe responsável pela validação de CPF / CNPJ
    /// </summary>
    internal class CPFCNPJValidator : Validator<string>
    {
        /// <summary>
        /// Indica tipo de validação selecionada
        /// </summary>
        CPFCNPJSelector _selected;

        /// <summary>
        /// Construtor da classe. 
        /// </summary>
        /// <param name="selected">Tipo da validação a ser realizada (CPF/CNPJ)</param>
        public CPFCNPJValidator(CPFCNPJSelector selected)
            : base(null, null)
        {
            _selected = selected;
        }

        /// <summary>
        /// Método de implementação requerida (abstract na classe base) que contém a regra de validação 
        /// </summary>
        /// <param name="objectToValidate"></param>
        /// <param name="currentTarget"></param>
        /// <param name="key"></param>
        /// <param name="validationResults"></param>
        protected override void DoValidate(string objectToValidate, object currentTarget, string key, ValidationResults validationResults)
        {
            bool validado;
            switch (_selected)
            {
                case CPFCNPJSelector.CPF:
                    validado = ValidarCPF(objectToValidate);
                    break;
                case CPFCNPJSelector.CNPJ: 
                    validado = ValidarCNPJ(objectToValidate);
                    break;
                default:
                    validado = (ValidarCPF(objectToValidate) || ValidarCNPJ(objectToValidate));
                    break;
            }

            if (!validado)
            {
                validationResults.AddResult(new ValidationResult(this.MessageTemplate, currentTarget, key, this.Tag, this));
            }
        }


        /// <summary>
        /// Valida um CPF
        /// </summary>
        /// <param name="CPF"></param>
        /// <returns></returns>
        private bool ValidarCPF(string cpf)
        {
            string Valor = cpf.Replace(".", "").Replace("-", "");

            if (Valor.Length != 11)
                return false;

            bool Igual = true;

            for (int i = 1; i < 11 && Igual; i++)
            {
                if (Valor[i] != Valor[0])
                    Igual = false;
            }

            if (Igual || Valor == "12345678909")
                return false;

            int[] Numeros = new int[11];

            for (int i = 0; i < 11; i++)
                Numeros[i] = int.Parse(Valor[i].ToString());

            int Soma = 0;

            for (int i = 0; i < 9; i++)
            {
                Soma += (10 - i) * Numeros[i];
            }

            int Resultado = Soma % 11;

            if (Resultado == 1 || Resultado == 0)
            {
                if (Numeros[9] != 0)
                    return false;
            }
            else
            {
                if (Numeros[9] != 11 - Resultado)
                    return false;
            }

            Soma = 0;

            for (int i = 0; i < 10; i++)
            {
                Soma += (11 - i) * Numeros[i];
            }

            Resultado = Soma % 11;

            if (Resultado == 1 || Resultado == 0)
            {
                if (Numeros[10] != 0)
                    return false;
            }
            else
            {
                if (Numeros[10] != 11 - Resultado)
                    return false;
            }

            return true;
        }


        /// <summary>
        /// Validar CNPJ
        /// </summary>
        /// <param name="cnpj">CNPJ a ser validado</param>
        /// <returns>True caso válido, false caso inválido</returns>
        /// <user></user>
        private bool ValidarCNPJ(string cnpj)
        {
            int[] Multiplicador1 = new int[12] { 5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2 };
            int[] Multiplicador2 = new int[13] { 6, 5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2 };
            int Soma;
            int Resto;
            string Digito;
            string TempCNPJ;

            cnpj = cnpj.Trim();
            cnpj = cnpj.Replace(".", "").Replace("-", "").Replace("/", "");

            if (cnpj.Length != 14)
                return false;

            TempCNPJ = cnpj.Substring(0, 12);

            Soma = 0;
            for (int i = 0; i < 12; i++)
            {
                Soma += int.Parse(TempCNPJ[i].ToString()) * Multiplicador1[i];
            }

            Resto = (Soma % 11);
            if (Resto < 2)
                Resto = 0;
            else
                Resto = 11 - Resto;

            Digito = Resto.ToString();

            TempCNPJ = TempCNPJ + Digito;
            Soma = 0;
            for (int i = 0; i < 13; i++)
            {
                Soma += int.Parse(TempCNPJ[i].ToString()) * Multiplicador2[i];
            }

            Resto = (Soma % 11);
            if (Resto < 2)
                Resto = 0;
            else
                Resto = 11 - Resto;

            Digito = Digito + Resto.ToString();

            return cnpj.EndsWith(Digito);
        }


        /// <summary>
        /// Método de implementação requerida (abstract na classe base) e que retorna DefaultMessageTemplate
        /// </summary>
        protected override string DefaultMessageTemplate
        {
            get { return ""; }
        }
    }
}
